﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using CDOP.Model;
using CDOP.Properties;

namespace CDOP.Utility
{
    public class Helper
    {

        public static string Encrypt(string textToBeEncrypted)
        {
            const string password = "CDOP";
            var encryptedData = GetEncryptedData(textToBeEncrypted, password);
            return encryptedData;
        }

        public static string Decrypt(string textToBeDecrypted)
        {
            var rijndaelCipher = new RijndaelManaged();

            const string password = "CDOP";
            string decryptedData;

            try
            {
                var encryptedData = Convert.FromBase64String(textToBeDecrypted);

                var salt = Encoding.ASCII.GetBytes(password.Length.ToString());
                //Making of the key for decryption
                var secretKey = new PasswordDeriveBytes(password, salt);
                //Creates a symmetric Rijndael decryptor object.
                var decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));

                var memoryStream = new MemoryStream(encryptedData);
                //Defines the cryptographics stream for decryption.THe stream contains decrpted data
                var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

                var plainText = new byte[encryptedData.Length];
                var decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);
                memoryStream.Close();
                cryptoStream.Close();

                //Converting to string
                decryptedData = Encoding.Unicode.GetString(plainText, 0, decryptedCount);
            }
            catch
            {
                decryptedData = textToBeDecrypted;
            }
            return decryptedData;
        }


        private static string GetEncryptedData(string textToBeEncrypted, string password)
        {
            var rijndaelCipher = new RijndaelManaged();
            var plainText = Encoding.Unicode.GetBytes(textToBeEncrypted);
            var salt = Encoding.ASCII.GetBytes(password.Length.ToString());
            var secretKey = new PasswordDeriveBytes(password, salt);
            //Creates a symmetric encrypt object. 
            var encryptor = rijndaelCipher.CreateEncryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));
            var memoryStream = new MemoryStream();
            //Defines a stream that links data streams to cryptographic transformations
            var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
            cryptoStream.Write(plainText, 0, plainText.Length);
            //Writes the final state and clears the buffer
            cryptoStream.FlushFinalBlock();
            var cipherBytes = memoryStream.ToArray();
            memoryStream.Close();
            cryptoStream.Close();
            return Convert.ToBase64String(cipherBytes);
        }

        public static string Encrypt(string textToBeEncrypted, string password)
        {
            var encryptedData = GetEncryptedData(textToBeEncrypted, password);
            return encryptedData;
        }

        public static void SendEmail(string to, string subject, string body)
        {
            var message = new MailMessage();
            message.To.Add(to);
            message.Subject = subject;
            message.From = new MailAddress(Settings.Default.EmailAddress);
            message.Body = body;
            message.IsBodyHtml = true;
            var smtp = new SmtpClient(Settings.Default.CurrentUrl, Settings.Default.SmtpPort)
                           {
                               Host = Settings.Default.SmtpHost,
                               Credentials =
                                   new NetworkCredential(Settings.Default.EmailAddress, Settings.Default.EmailPassword),
                               DeliveryMethod = SmtpDeliveryMethod.Network,
                               EnableSsl = true
                           };
            smtp.Send(message);
        }

        public static string EncodeUrl(string toEncode)
        {
            const string pattern = "[$&+,/:;=?@]";
            var match = Regex.Match(toEncode, pattern);
            while (match.Success)
            {
                toEncode = toEncode.Replace(match.Value, Uri.EscapeDataString(match.Value));
                match = Regex.Match(toEncode, pattern);
            }
            return toEncode;
        }

        public static DataTable ConvertTo<T>(IList<T> list)
        {
            var table = CreateTable<T>();
            var entityType = typeof(T);
            var properties = TypeDescriptor.GetProperties(entityType);

            foreach (T item in list)
            {
                var row = table.NewRow();

                foreach (PropertyDescriptor prop in properties)
                {
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                }

                table.Rows.Add(row);
            }

            return table;
        }

        public static DataTable ConvertTo<T>(IList<T> list, string pageName)
        {
            var table = CreateTable<T>(pageName);
            var entityType = typeof(T);
            var allProperties = TypeDescriptor.GetProperties(entityType);
            var neededProperties = GetRelevantProperties(allProperties, pageName);

            foreach (T item in list)
            {
                var row = table.NewRow();

                foreach (PropertyDescriptor prop in neededProperties)
                {
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                }

                table.Rows.Add(row);
            }

            return table;
        }

        public static DataTable CreateTable<T>(string pageName)
        {
            var entityType = typeof(T);
            var table = new DataTable(entityType.Name);
            var allProperties = TypeDescriptor.GetProperties(entityType);
            var neededProperties = GetRelevantProperties(allProperties, pageName);
            foreach (PropertyDescriptor prop in neededProperties)
            {
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }

            return table;
        }

        public static DataTable CreateTable<T>()
        {
            var entityType = typeof(T);
            var table = new DataTable(entityType.Name);
            var properties = TypeDescriptor.GetProperties(entityType);
            foreach (PropertyDescriptor prop in properties)
            {
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }

            return table;
        }

        public static IEnumerable<PropertyDescriptor> GetRelevantProperties(PropertyDescriptorCollection allProperties)
        {
            var allNames = (from PropertyDescriptor property in allProperties
                            select property.Name).ToList();
            var removeNames = new List<string> { "EntityState", "EntityKey" };
            var relevantNames = allNames.Except(removeNames);
            var neededProperties = allProperties.Cast<PropertyDescriptor>().Where(property => relevantNames.Contains(property.Name)).ToList();
            return neededProperties;
        }

        public static IEnumerable<PropertyDescriptor> GetRelevantProperties(PropertyDescriptorCollection allProperties, string pageName)
        {
            var allNames = (from PropertyDescriptor property in allProperties
                            select property.Name).ToList();
            var allowedNames = new ExportCustomizationRepository().GetByPageName(pageName).Select(x => x.Name).ToList();
            var relevantNames = allNames.Intersect(allowedNames);
            var neededProperties = allProperties.Cast<PropertyDescriptor>().Where(property => relevantNames.Contains(property.Name)).ToList();
            return neededProperties;
        }

    }
}